#!/usr/bin/python -O

import sys,os
import wx

from qpid.messaging import *
from threading import Thread, Lock
import time

import sqlite3
from amqp import RoutingKey

FONTSIZE=10
DBNAME='qpid.db3'

def getProtoClass(msgName, pubName):

    module = __import__(msgName + '_pb2', globals(), locals(), [pubName])

    return getattr(module, pubName)

class Receiver(Thread):
    def __init__(self, ip, port, lstKeys):
        Thread.__init__(self)

        self.__ip = ip
        self.__port = port
        self.__lstKeys = lstKeys

        self.__go = True
        self.__count=0

    def run(self):
        broker = '%s:%s' % (self.__ip, self.__port)
        address = 'amq.topic'

        connection = Connection(broker)

        connection.open()
        session = connection.session()
   
        receiver = session.receiver(address)
   
        db = sqlite3.connect(DBNAME)
        cur = db.cursor()
        while self.__go:
            message = receiver.fetch()
            self.__count += 1
	  
            routingKeyStr = message.properties['x-amqp-0-10.routing-key'];


            timestr = time.strftime('[%Y-%m-%d_%H:%M:%S]:')
            msgstr = timestr + routingKeyStr

            self.__lstKeys.AppendItems([msgstr])

            #print message.properties
            routingKey = RoutingKey(routingKeyStr)

            msgName = routingKey.GetAsMessageName()
            pubName = routingKey.GetPublicationName()
            myClass = getProtoClass(msgName, pubName)

            msg = myClass()
            msg.ParseFromString(message.content)

            detail = str(msg).replace('\n', '__NEWLINE__');
            cur.execute("INSERT INTO msg_t VALUES(?, ?)",  (msgstr, detail))

            db.commit()
        else:
            connection.close()         
            print "Stopping"

    def stop(self):
        self.__go = False

class PubFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(PubFrame, self).__init__(*args, **kwargs)

        self.__txtPub = wx.TextCtrl(self, style=wx.TE_MULTILINE)
        self.__txtPub.SetEditable(False)
        self.SetSize((600,400))

    def SetText(self, txt):
        db = sqlite3.connect(DBNAME)

        cur = db.cursor()
        cur.execute("SELECT msg_detail FROM msg_t WHERE msg_k=?", (txt,))
        row = cur.fetchone()
        msg_detail = row[0].encode('ascii').replace('__NEWLINE__', '\n')

        self.__txtPub.Clear()
        self.__txtPub.SetValue(txt + '\n' + msg_detail)
    
class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        super(MyFrame, self).__init__(parent, title=title)

        self.__db = sqlite3.connect(DBNAME)
        self.__receiver = None

        self.InitUI()

        self.SetSize((800,600))
        self.Center()
        self.Show()

    def InitUI(self):
        font = wx.Font(FONTSIZE, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)

        panel = wx.Panel(self)

        vbox = wx.BoxSizer(wx.VERTICAL);
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)

        st1 = wx.StaticText(panel, label='Host name:')
        st1.SetFont(font)
        hbox1.Add(st1, flag=wx.LEFT|wx.RIGHT|wx.TOP, border=5)

        self.Host = wx.ComboBox(panel, style=wx.CB_SORT|wx.TE_PROCESS_ENTER)
        self.Host.SetFont(font)

        cur = self.__db.cursor()
       
        for host in cur.execute('SELECT host from host_t'):
            self.Host.AppendItems([host[0].encode('ascii')])
        cur.close()

        if self.Host.GetCount() > 0: self.Host.SetSelection(0)

        self.Host.Bind(wx.EVT_TEXT_ENTER, self.OnHostPortEntered)
        hbox1.Add(self.Host, proportion=1, flag=wx.LEFT|wx.TOP, border=3)

        st2 = wx.StaticText(panel, label='Port:')
        st2.SetFont(font)
        hbox1.Add(st2, flag=wx.LEFT|wx.RIGHT|wx.TOP, border=5)

        self.Port = wx.ComboBox(panel, style=wx.CB_SORT|wx.TE_PROCESS_ENTER)
        self.Port.SetFont(font)

        for port in cur.execute('SELECT port from port_t'):
            self.Port.AppendItems([str(port[0])])
        cur.close()

        if self.Port.GetCount() > 0: self.Port.SetSelection(0)

        self.Port.Bind(wx.EVT_TEXT_ENTER, self.OnHostPortEntered)
        hbox1.Add(self.Port, proportion=1, flag=wx.LEFT|wx.TOP, border=3)

        self.btnStart = wx.Button(panel, wx.ID_ANY, 'Start', (70,FONTSIZE*2))
        self.btnStart.SetFont(font)
        self.btnStart.Bind(wx.EVT_BUTTON, self.OnStartClick)
        hbox1.Add(self.btnStart, flag=wx.LEFT|wx.TOP|wx.RIGHT, border=2)

        self.btnStop = wx.Button(panel, wx.ID_ANY, 'Stop', (70,FONTSIZE*2))
        self.btnStop.SetFont(font)
        self.btnStop.Bind(wx.EVT_BUTTON, self.OnStopClick)
        self.btnStop.Disable();
        hbox1.Add(self.btnStop, flag=wx.LEFT|wx.TOP|wx.RIGHT, border=2)
        
        vbox.Add(hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=2)

        hbox3 = wx.BoxSizer(wx.HORIZONTAL);
        self.lstKeys = wx.ListBox(panel)
        self.lstKeys.SetFont(font)
        self.lstKeys.Bind(wx.EVT_LISTBOX_DCLICK, self.OnLstKeysDbclick)

        hbox3.Add(self.lstKeys, proportion=1, flag=wx.EXPAND)
        vbox.Add(hbox3, proportion=1, flag=wx.EXPAND|wx.ALL, border=2)
        
        panel.SetSizer(vbox)

    def OnHostPortEntered(self, e):
        if self.Host.GetSelection() == -1:
            host = self.Host.GetValue()
            if self.Host.FindString(host) == wx.NOT_FOUND:
                self.Host.AppendItems([host])

        if self.Port.GetSelection() == -1:
            port = self.Port.GetValue()
            if self.Port.FindString(port) == wx.NOT_FOUND:
                self.Port.AppendItems([port])

    def OnStartClick(self, e):

        self.btnStart.Disable()
        self.btnStop.Enable()

        host = self.Host.GetValue()
        port = self.Port.GetValue()

        self.__receiver = Receiver(host, port, self.lstKeys)
        self.__receiver.daemon = True

        self.__receiver.start()

    def OnStopClick(self, e):
        self.__receiver.stop()

        self.btnStart.Enable()
        self.btnStop.Disable()

    def OnLstKeysDbclick(self, e):
        index = self.lstKeys.GetSelection()
        item = self.lstKeys.GetString(index)

        frmPub  = PubFrame(self, title='Publication detail')
        frmPub.SetText(item)
        frmPub.Show()   

        pass

if __name__ == '__main__':

    ProtoSrc = os.path.join(os.environ['HOME'], 'protos')
    sys.path.insert(0, ProtoSrc)

    app = wx.App(redirect=False)

    conn = sqlite3.connect('qpid.db3')

    MyFrame(None,title='Qpid Monitor')

    app.MainLoop()

